package com.zenithmind.mall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.exception.BusinessException;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.mall.mapper.UserCouponMapper;
import com.zenithmind.mall.mapper.CouponMapper;
import com.zenithmind.mall.pojo.entity.UserCoupon;
import com.zenithmind.mall.pojo.entity.Coupon;
import com.zenithmind.mall.pojo.query.UserCouponQuery;
import com.zenithmind.mall.pojo.vo.UserCouponVO;
import com.zenithmind.mall.service.UserCouponService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户优惠券服务实现
 * 
 * @author ZenithMind Team
 * @since 2025-06-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserCouponServiceImpl extends ServiceImpl<UserCouponMapper, UserCoupon> implements UserCouponService {

    private final CouponMapper couponMapper;

    @Override
    public PageResult<UserCouponVO> getUserCouponPage(UserCouponQuery query) {
        Page<UserCoupon> page = new Page<>(query.getCurrent(), query.getSize());
        
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getIsDeleted, 0)
               .eq(StringUtils.hasText(query.getUserId()), UserCoupon::getUserId, query.getUserId())
               .eq(StringUtils.hasText(query.getCouponId()), UserCoupon::getCouponId, query.getCouponId())
               .eq(query.getStatus() != null, UserCoupon::getStatus, query.getStatus())
               .ge(query.getReceiveStartTime() != null, UserCoupon::getReceiveTime, query.getReceiveStartTime())
               .le(query.getReceiveEndTime() != null, UserCoupon::getReceiveTime, query.getReceiveEndTime())
               .ge(query.getUseStartTime() != null, UserCoupon::getUseTime, query.getUseStartTime())
               .le(query.getUseEndTime() != null, UserCoupon::getUseTime, query.getUseEndTime())
               .ge(query.getValidStartTime() != null, UserCoupon::getStartTime, query.getValidStartTime())
               .le(query.getValidEndTime() != null, UserCoupon::getEndTime, query.getValidEndTime());

        // 处理可用性筛选
        if (query.getAvailable() != null) {
            LocalDateTime now = LocalDateTime.now();
            if (query.getAvailable()) {
                wrapper.eq(UserCoupon::getStatus, 0)
                       .le(UserCoupon::getStartTime, now)
                       .ge(UserCoupon::getEndTime, now);
            } else {
                wrapper.and(w -> w.ne(UserCoupon::getStatus, 0)
                                 .or().gt(UserCoupon::getStartTime, now)
                                 .or().lt(UserCoupon::getEndTime, now));
            }
        }

        // 处理即将过期筛选
        if (query.getExpireDays() != null) {
            LocalDateTime expireTime = LocalDateTime.now().plusDays(query.getExpireDays());
            wrapper.le(UserCoupon::getEndTime, expireTime)
                   .eq(UserCoupon::getStatus, 0);
        }

        // 排序
        if (StringUtils.hasText(query.getSortField())) {
            boolean isAsc = "asc".equalsIgnoreCase(query.getSortOrder());
            switch (query.getSortField()) {
                case "useTime":
                    wrapper.orderBy(true, isAsc, UserCoupon::getUseTime);
                    break;
                case "endTime":
                    wrapper.orderBy(true, isAsc, UserCoupon::getEndTime);
                    break;
                default:
                    wrapper.orderByDesc(UserCoupon::getReceiveTime);
            }
        } else {
            wrapper.orderByDesc(UserCoupon::getReceiveTime);
        }

        Page<UserCoupon> result = page(page, wrapper);

        // 转换为VO
        List<UserCouponVO> voList = result.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());

        return new PageResult<>(voList, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public UserCouponVO getUserCouponById(String id, String userId) {
        UserCoupon userCoupon = getById(id);
        if (userCoupon == null || !userCoupon.getUserId().equals(userId)) {
            throw new BusinessException("用户优惠券不存在");
        }
        return convertToVO(userCoupon);
    }

    @Override
    public List<UserCouponVO> getUserCouponList(String userId, Integer status) {
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getUserId, userId)
               .eq(UserCoupon::getIsDeleted, 0)
               .eq(status != null, UserCoupon::getStatus, status)
               .orderByDesc(UserCoupon::getReceiveTime);

        List<UserCoupon> userCoupons = list(wrapper);
        return userCoupons.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    @Override
    public List<UserCouponVO> getAvailableUserCoupons(String userId, BigDecimal orderAmount) {
        LocalDateTime now = LocalDateTime.now();
        
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getUserId, userId)
               .eq(UserCoupon::getIsDeleted, 0)
               .eq(UserCoupon::getStatus, 0) // 未使用
               .le(UserCoupon::getStartTime, now)
               .ge(UserCoupon::getEndTime, now)
               .orderByDesc(UserCoupon::getReceiveTime);

        List<UserCoupon> userCoupons = list(wrapper);
        
        // 过滤满足订单金额条件的优惠券
        return userCoupons.stream()
                .filter(userCoupon -> {
                    Coupon coupon = couponMapper.selectById(userCoupon.getCouponId());
                    return coupon != null && orderAmount.compareTo(coupon.getMinAmount()) >= 0;
                })
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean useUserCoupon(String id, String orderId, String userId) {
        UserCoupon userCoupon = getById(id);
        if (userCoupon == null || !userCoupon.getUserId().equals(userId)) {
            throw new BusinessException("用户优惠券不存在");
        }

        if (userCoupon.getStatus() != 0) {
            throw new BusinessException("优惠券已使用或已过期");
        }

        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(userCoupon.getStartTime()) || now.isAfter(userCoupon.getEndTime())) {
            throw new BusinessException("优惠券不在有效期内");
        }

        userCoupon.setStatus(1); // 已使用
        userCoupon.setOrderId(orderId);
        userCoupon.setUseTime(now);
        userCoupon.setUpdateBy(userId);

        boolean result = updateById(userCoupon);
        if (result) {
            log.info("使用用户优惠券成功: {}", id);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean returnUserCoupon(String id, String userId) {
        UserCoupon userCoupon = getById(id);
        if (userCoupon == null || !userCoupon.getUserId().equals(userId)) {
            throw new BusinessException("用户优惠券不存在");
        }

        if (userCoupon.getStatus() != 1) {
            throw new BusinessException("只能退还已使用的优惠券");
        }

        // 检查是否在有效期内
        LocalDateTime now = LocalDateTime.now();
        if (now.isAfter(userCoupon.getEndTime())) {
            throw new BusinessException("优惠券已过期，无法退还");
        }

        userCoupon.setStatus(0); // 未使用
        userCoupon.setOrderId(null);
        userCoupon.setUseTime(null);
        userCoupon.setUpdateBy(userId);

        boolean result = updateById(userCoupon);
        if (result) {
            log.info("退还用户优惠券成功: {}", id);
        }
        return result;
    }

    @Override
    public Boolean checkUserCouponAvailable(String id, String userId, BigDecimal orderAmount) {
        UserCoupon userCoupon = getById(id);
        if (userCoupon == null || !userCoupon.getUserId().equals(userId)) {
            return false;
        }

        if (userCoupon.getStatus() != 0) {
            return false;
        }

        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(userCoupon.getStartTime()) || now.isAfter(userCoupon.getEndTime())) {
            return false;
        }

        // 检查订单金额是否满足条件
        Coupon coupon = couponMapper.selectById(userCoupon.getCouponId());
        if (coupon == null) {
            return false;
        }

        return orderAmount.compareTo(coupon.getMinAmount()) >= 0;
    }

    @Override
    public BigDecimal calculateDiscountAmount(String id, String userId, BigDecimal orderAmount) {
        if (!checkUserCouponAvailable(id, userId, orderAmount)) {
            return BigDecimal.ZERO;
        }

        UserCoupon userCoupon = getById(id);
        Coupon coupon = couponMapper.selectById(userCoupon.getCouponId());

        if (coupon == null) {
            return BigDecimal.ZERO;
        }

        BigDecimal discountAmount = BigDecimal.ZERO;
        
        switch (coupon.getType()) {
            case 1: // 满减券
                discountAmount = coupon.getAmount();
                break;
            case 2: // 折扣券
                discountAmount = orderAmount.multiply(BigDecimal.ONE.subtract(coupon.getDiscountRate()));
                break;
            case 3: // 免邮券
                // 免邮券的优惠金额需要根据实际运费计算，这里暂时返回0
                discountAmount = BigDecimal.ZERO;
                break;
        }

        // 确保优惠金额不超过订单金额
        return discountAmount.min(orderAmount);
    }

    /**
     * 转换为VO
     */
    private UserCouponVO convertToVO(UserCoupon userCoupon) {
        UserCouponVO vo = new UserCouponVO();
        BeanUtils.copyProperties(userCoupon, vo);

        // 获取优惠券信息
        Coupon coupon = couponMapper.selectById(userCoupon.getCouponId());
        if (coupon != null) {
            vo.setCouponName(coupon.getName());
            vo.setCouponDescription(coupon.getDescription());
            vo.setCouponType(coupon.getType());
            vo.setDiscountAmount(coupon.getAmount());
            vo.setDiscountRate(coupon.getDiscountRate());
            vo.setMinAmount(coupon.getMinAmount());
            vo.setApplicableScope(coupon.getApplicableType());
            vo.setApplicableProductIds(coupon.getApplicableProducts());
            vo.setApplicableCategoryIds(coupon.getApplicableCategories());
        }

        // 设置状态文本
        vo.setStatusText(getStatusText(userCoupon.getStatus()));
        vo.setCouponTypeText(getCouponTypeText(coupon != null ? coupon.getType() : null));

        // 计算可用性
        LocalDateTime now = LocalDateTime.now();
        boolean available = userCoupon.getStatus() == 0 
                && !now.isBefore(userCoupon.getStartTime()) 
                && !now.isAfter(userCoupon.getEndTime());
        vo.setAvailable(available);

        if (!available) {
            if (userCoupon.getStatus() != 0) {
                vo.setUnavailableReason(userCoupon.getStatus() == 1 ? "已使用" : "已过期");
            } else if (now.isBefore(userCoupon.getStartTime())) {
                vo.setUnavailableReason("未到使用时间");
            } else if (now.isAfter(userCoupon.getEndTime())) {
                vo.setUnavailableReason("已过期");
            }
        }

        // 计算剩余天数
        if (userCoupon.getEndTime() != null) {
            long remainingDays = ChronoUnit.DAYS.between(now, userCoupon.getEndTime());
            vo.setRemainingDays(Math.max(0, remainingDays));
        }

        return vo;
    }

    /**
     * 获取状态文本
     */
    private String getStatusText(Integer status) {
        if (status == null) return "未知";
        return switch (status) {
            case 0 -> "未使用";
            case 1 -> "已使用";
            case 2 -> "已过期";
            default -> "未知";
        };
    }

    /**
     * 获取优惠券类型文本
     */
    private String getCouponTypeText(Integer type) {
        if (type == null) return "未知";
        return switch (type) {
            case 1 -> "满减券";
            case 2 -> "折扣券";
            case 3 -> "免邮券";
            default -> "未知";
        };
    }

    @Override
    public UserCouponStatistics getUserCouponStatistics(String userId) {
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getUserId, userId)
               .eq(UserCoupon::getIsDeleted, 0);

        List<UserCoupon> userCoupons = list(wrapper);

        long totalCount = userCoupons.size();
        long usedCount = userCoupons.stream().filter(uc -> uc.getStatus() == 1).count();
        long expiredCount = userCoupons.stream().filter(uc -> uc.getStatus() == 2).count();

        LocalDateTime now = LocalDateTime.now();
        long availableCount = userCoupons.stream()
                .filter(uc -> uc.getStatus() == 0
                        && !now.isBefore(uc.getStartTime())
                        && !now.isAfter(uc.getEndTime()))
                .count();

        return new UserCouponStatistics(totalCount, availableCount, usedCount, expiredCount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer expireUserCoupons() {
        LocalDateTime now = LocalDateTime.now();

        LambdaUpdateWrapper<UserCoupon> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(UserCoupon::getStatus, 0) // 未使用
               .lt(UserCoupon::getEndTime, now) // 已过期
               .set(UserCoupon::getStatus, 2); // 设置为已过期

        int count = Math.toIntExact(count(new LambdaQueryWrapper<UserCoupon>()
                .eq(UserCoupon::getStatus, 0)
                .lt(UserCoupon::getEndTime, now)));

        if (count > 0) {
            update(wrapper);
            log.info("过期用户优惠券数量: {}", count);
        }

        return count;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteUserCoupon(String id, String userId) {
        UserCoupon userCoupon = getById(id);
        if (userCoupon == null || !userCoupon.getUserId().equals(userId)) {
            throw new BusinessException("用户优惠券不存在");
        }

        if (userCoupon.getStatus() == 1) {
            throw new BusinessException("已使用的优惠券无法删除");
        }

        boolean result = removeById(id);
        if (result) {
            log.info("删除用户优惠券成功: {}", id);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteUserCouponsBatch(List<String> ids, String userId) {
        if (ids == null || ids.isEmpty()) {
            return true;
        }

        // 验证所有优惠券都属于当前用户且未使用
        List<UserCoupon> userCoupons = listByIds(ids);
        boolean allBelongToUser = userCoupons.stream()
                .allMatch(uc -> uc.getUserId().equals(userId) && uc.getStatus() != 1);

        if (!allBelongToUser) {
            throw new BusinessException("包含不属于当前用户或已使用的优惠券");
        }

        boolean result = removeByIds(ids);
        if (result) {
            log.info("批量删除用户优惠券成功: {}", ids);
        }
        return result;
    }
}
